/**
 * 优化的RPG数据访问层
 * 使用统一缓存系统，减少重复代码，提供批量查询功能
 */

import { ModernBaseService } from '../service/base/ModernBaseService';
import { RepositoryHelper } from '../infrastructure/repository/RepositoryHelper';
import { SkillUse, ActiveBuff } from '../core/rpg/types';
import { Attribute_base } from '../shared/face/enums';

/**
 * 玩家RPG数据接口
 */
interface PlayerRPGData {
    playerId: string;
    level: number;
    experience: number;
    attributes: Record<string, number>;
    skills: SkillUse[];
    buffs: ActiveBuff[];
    stats: PlayerStats;
    lastUpdated: Date;
}

/**
 * 玩家统计数据
 */
interface PlayerStats {
    totalDamageDealt: number;
    totalDamageTaken: number;
    battlesWon: number;
    battlesLost: number;
    skillsUsed: number;
    monstersKilled: number;
}

/**
 * 优化的RPG Repository
 * 使用统一的缓存和批量查询
 */
export class OptimizedRPGRepository extends ModernBaseService {
    private readonly CACHE_TTL = 300000; // 5分钟缓存
    private readonly STATS_CACHE_TTL = 60000; // 统计数据1分钟缓存
    private readonly CACHE_PREFIX = 'rpg';

    /**
     * 获取玩家RPG数据
     * 使用统一缓存系统
     */
    async getPlayerRPGData(playerId: string): Promise<PlayerRPGData> {
        RepositoryHelper.validateRequiredParams({ playerId }, ['playerId']);
        
        const cacheKey = RepositoryHelper.buildCacheKey(this.CACHE_PREFIX, playerId);
        
        return RepositoryHelper.withCache(
            cacheKey,
            () => this.loadRPGFromSource(playerId),
            this.CACHE_TTL
        );
    }

    /**
     * 批量获取多个玩家的RPG数据
     * 优化查询，避免N+1问题
     */
    async getPlayerRPGDataBatch(playerIds: string[]): Promise<Map<string, PlayerRPGData>> {
        if (playerIds.length === 0) {
            return new Map();
        }
        
        return RepositoryHelper.batchGet(
            playerIds,
            this.CACHE_PREFIX,
            (uncachedIds) => this.batchLoadRPGData(uncachedIds),
            this.CACHE_TTL
        );
    }

    /**
     * 获取玩家RPG数据（保持顺序）
     */
    async getPlayerRPGDataOrdered(playerIds: string[]): Promise<(PlayerRPGData | null)[]> {
        if (playerIds.length === 0) {
            return [];
        }
        
        return RepositoryHelper.batchGetOrdered(
            playerIds,
            this.CACHE_PREFIX,
            (uncachedIds) => this.batchLoadRPGData(uncachedIds),
            this.CACHE_TTL
        );
    }

    /**
     * 更新玩家RPG数据
     * 更新后刷新缓存
     */
    async updatePlayerRPGData(playerId: string, updateData: Partial<PlayerRPGData>): Promise<PlayerRPGData> {
        RepositoryHelper.validateRequiredParams({ playerId }, ['playerId']);
        
        // 先获取当前数据
        const currentData = await this.getPlayerRPGData(playerId);
        
        // 合并更新数据
        const updatedData = {
            ...currentData,
            ...updateData,
            lastUpdated: new Date()
        };
        
        // 保存到数据源
        await this.saveRPGToSource(playerId, updatedData);
        
        // 刷新缓存
        const cacheKey = RepositoryHelper.buildCacheKey(this.CACHE_PREFIX, playerId);
        return RepositoryHelper.refreshCache(
            cacheKey,
            () => Promise.resolve(updatedData),
            this.CACHE_TTL
        );
    }

    /**
     * 增加玩家经验
     * 优化的经验操作
     */
    async addExperience(playerId: string, expGain: number): Promise<PlayerRPGData> {
        const rpgData = await this.getPlayerRPGData(playerId);
        
        // 计算新经验和等级
        let newExp = rpgData.experience + expGain;
        let newLevel = rpgData.level;
        
        // 检查是否升级
        while (newExp >= this.getExpNeededForLevel(newLevel + 1) && newLevel < 100) {
            newExp -= this.getExpNeededForLevel(newLevel + 1);
            newLevel++;
        }
        
        return this.updatePlayerRPGData(playerId, {
            level: newLevel,
            experience: newExp
        });
    }

    /**
     * 学习技能
     */
    async learnSkill(playerId: string, skillId: string): Promise<PlayerRPGData> {
        const rpgData = await this.getPlayerRPGData(playerId);
        
        // 检查是否已经学会
        const existingSkill = rpgData.skills.find(skill => skill.skillId === skillId);
        if (existingSkill) {
            throw new Error(`Skill ${skillId} already learned`);
        }
        
        // 添加新技能
        const newSkill: SkillUse = {
            skillId,
            level: 1,
            exp: 0,
            useCount: 0,
            permanentBoosts: {}
        };
        
        const updatedSkills = [...rpgData.skills, newSkill];
        
        return this.updatePlayerRPGData(playerId, {
            skills: updatedSkills
        });
    }

    /**
     * 升级技能
     */
    async upgradeSkill(playerId: string, skillId: string, expGain: number): Promise<PlayerRPGData> {
        const rpgData = await this.getPlayerRPGData(playerId);
        
        const skillIndex = rpgData.skills.findIndex(skill => skill.skillId === skillId);
        if (skillIndex === -1) {
            throw new Error(`Skill ${skillId} not found`);
        }
        
        const skill = rpgData.skills[skillIndex];
        const newExp = skill.exp + expGain;
        
        // 计算新等级
        let newLevel = skill.level;
        let remainingExp = newExp;
        
        while (remainingExp >= this.getSkillExpNeeded(newLevel) && newLevel < 10) {
            remainingExp -= this.getSkillExpNeeded(newLevel);
            newLevel++;
        }
        
        // 更新技能
        const updatedSkills = [...rpgData.skills];
        updatedSkills[skillIndex] = {
            ...skill,
            level: newLevel,
            exp: remainingExp
        };
        
        return this.updatePlayerRPGData(playerId, {
            skills: updatedSkills
        });
    }

    /**
     * 获取玩家统计数据
     * 使用单独的缓存策略
     */
    async getPlayerStats(playerId: string): Promise<PlayerStats> {
        const cacheKey = RepositoryHelper.buildCacheKey('rpg_stats', playerId);
        
        return RepositoryHelper.withCache(
            cacheKey,
            async () => {
                const rpgData = await this.getPlayerRPGData(playerId);
                return rpgData.stats;
            },
            this.STATS_CACHE_TTL
        );
    }

    /**
     * 更新战斗统计
     */
    async updateBattleStats(playerId: string, battleResult: {
        damageDealt: number;
        damageTaken: number;
        isWin: boolean;
        skillsUsed: number;
        monstersKilled: number;
    }): Promise<void> {
        const rpgData = await this.getPlayerRPGData(playerId);
        
        const updatedStats: PlayerStats = {
            totalDamageDealt: rpgData.stats.totalDamageDealt + battleResult.damageDealt,
            totalDamageTaken: rpgData.stats.totalDamageTaken + battleResult.damageTaken,
            battlesWon: rpgData.stats.battlesWon + (battleResult.isWin ? 1 : 0),
            battlesLost: rpgData.stats.battlesLost + (battleResult.isWin ? 0 : 1),
            skillsUsed: rpgData.stats.skillsUsed + battleResult.skillsUsed,
            monstersKilled: rpgData.stats.monstersKilled + battleResult.monstersKilled
        };
        
        await this.updatePlayerRPGData(playerId, { stats: updatedStats });
        
        // 清除统计缓存
        const statsCacheKey = RepositoryHelper.buildCacheKey('rpg_stats', playerId);
        RepositoryHelper.invalidateCache(statsCacheKey);
    }

    /**
     * 获取排行榜数据
     * 分页缓存查询
     */
    async getLeaderboard(
        type: 'level' | 'damage' | 'battles_won',
        page: number = 1,
        pageSize: number = 10
    ): Promise<{ data: Array<{ playerId: string; value: number; rank: number }>; total: number }> {
        return RepositoryHelper.cachedPageQuery(
            'rpg_leaderboard',
            page,
            pageSize,
            { type },
            async () => {
                // 这里应该从数据库查询排行榜数据
                // 暂时返回模拟数据
                const mockData = Array.from({ length: pageSize }, (_, i) => ({
                    playerId: `player_${page * pageSize + i}`,
                    value: Math.floor(Math.random() * 1000),
                    rank: (page - 1) * pageSize + i + 1
                }));
                
                return {
                    data: mockData,
                    total: 1000 // 模拟总数
                };
            },
            30000 // 排行榜缓存30秒
        );
    }

    /**
     * 清空RPG缓存
     */
    clearRPGCache(playerId?: string): number {
        if (playerId) {
            const rpgCacheKey = RepositoryHelper.buildCacheKey(this.CACHE_PREFIX, playerId);
            const statsCacheKey = RepositoryHelper.buildCacheKey('rpg_stats', playerId);
            let cleared = 0;
            if (RepositoryHelper.invalidateCache(rpgCacheKey)) cleared++;
            if (RepositoryHelper.invalidateCache(statsCacheKey)) cleared++;
            return cleared;
        } else {
            return RepositoryHelper.invalidateCacheByPrefix(`${this.CACHE_PREFIX}:`) +
                   RepositoryHelper.invalidateCacheByPrefix('rpg_stats:');
        }
    }

    /**
     * 预热RPG缓存
     */
    async warmupRPGCache(playerIds: string[]): Promise<void> {
        const warmupPromises = playerIds.map(async playerId => {
            const cacheKey = RepositoryHelper.buildCacheKey(this.CACHE_PREFIX, playerId);
            await RepositoryHelper.warmupCache(
                cacheKey,
                () => this.loadRPGFromSource(playerId),
                this.CACHE_TTL
            );
        });
        
        await Promise.allSettled(warmupPromises);
    }

    // ==================== 私有方法 ====================

    /**
     * 从数据源加载RPG数据
     */
    private async loadRPGFromSource(playerId: string): Promise<PlayerRPGData> {
        const player = this.sdk.getPlayerById(playerId);
        if (!player) {
            throw new Error(`Player ${playerId} not found`);
        }

        const rpgComponent = player.getComponent('RPG');
        if (!rpgComponent) {
            return this.createDefaultRPGData(playerId);
        }

        return {
            playerId,
            level: rpgComponent.level || 1,
            experience: rpgComponent.exp || 0,
            attributes: this.convertAttributes(rpgComponent),
            skills: this.convertSkillsToEntities(rpgComponent.skills || []),
            buffs: this.convertBuffs(rpgComponent.buffs || []),
            stats: this.calculateStats(rpgComponent),
            lastUpdated: new Date()
        };
    }

    /**
     * 批量加载RPG数据
     */
    private async batchLoadRPGData(playerIds: string[]): Promise<Map<string, PlayerRPGData>> {
        const result = new Map<string, PlayerRPGData>();
        
        const loadPromises = playerIds.map(async playerId => {
            try {
                const rpgData = await this.loadRPGFromSource(playerId);
                result.set(playerId, rpgData);
            } catch (error) {
                console.warn(`Failed to load RPG data for player ${playerId}:`, error);
                try {
                    const defaultRPG = this.createDefaultRPGData(playerId);
                    result.set(playerId, defaultRPG);
                } catch (defaultError) {
                    console.error(`Failed to create default RPG data for player ${playerId}:`, defaultError);
                }
            }
        });
        
        await Promise.allSettled(loadPromises);
        return result;
    }

    /**
     * 保存RPG数据到数据源
     */
    private async saveRPGToSource(playerId: string, rpgData: PlayerRPGData): Promise<void> {
        const player = this.sdk.getPlayerById(playerId);
        if (!player) {
            throw new Error(`Player ${playerId} not found`);
        }

        let rpgComponent = player.getComponent('RPG');
        if (!rpgComponent) {
            rpgComponent = player.addComponent('RPG');
        }

        // 更新组件数据
        rpgComponent.level = rpgData.level;
        rpgComponent.exp = rpgData.experience;
        rpgComponent.skills = rpgData.skills;
        rpgComponent.buffs = rpgData.buffs;
        
        // 更新属性
        for (const [attr, value] of Object.entries(rpgData.attributes)) {
            rpgComponent.setAttribute(attr, value);
        }
    }

    /**
     * 创建默认RPG数据
     */
    private createDefaultRPGData(playerId: string): PlayerRPGData {
        return {
            playerId,
            level: 1,
            experience: 0,
            attributes: {
                [Attribute_base.攻击力]: 10,
                [Attribute_base.防御力]: 5,
                [Attribute_base.最大生命值]: 100,
                [Attribute_base.最大法力值]: 50
            },
            skills: [],
            buffs: [],
            stats: {
                totalDamageDealt: 0,
                totalDamageTaken: 0,
                battlesWon: 0,
                battlesLost: 0,
                skillsUsed: 0,
                monstersKilled: 0
            },
            lastUpdated: new Date()
        };
    }

    /**
     * 转换属性数据
     */
    private convertAttributes(rpgComponent: any): Record<string, number> {
        const attributes: Record<string, number> = {};
        
        // 从RPG组件获取所有属性
        for (const attr in Attribute_base) {
            const value = rpgComponent.getAttribute(attr);
            if (typeof value === 'number') {
                attributes[attr] = value;
            }
        }
        
        return attributes;
    }

    /**
     * 转换技能数据
     */
    private convertSkillsToEntities(skills: any[]): SkillUse[] {
        return skills.map(skill => ({
            skillId: skill.skillId,
            level: skill.level || 1,
            exp: skill.exp || 0,
            useCount: skill.useCount || 0,
            permanentBoosts: skill.permanentBoosts || {}
        }));
    }

    /**
     * 转换Buff数据
     */
    private convertBuffs(buffs: any[]): ActiveBuff[] {
        return buffs.map(buff => ({
            buffId: buff.buffId,
            duration: buff.duration,
            stackCount: buff.stackCount || 1,
            source: buff.source || 'unknown'
        }));
    }

    /**
     * 计算统计数据
     */
    private calculateStats(rpgComponent: any): PlayerStats {
        return {
            totalDamageDealt: rpgComponent.totalDamageDealt || 0,
            totalDamageTaken: rpgComponent.totalDamageTaken || 0,
            battlesWon: rpgComponent.battlesWon || 0,
            battlesLost: rpgComponent.battlesLost || 0,
            skillsUsed: rpgComponent.skillsUsed || 0,
            monstersKilled: rpgComponent.monstersKilled || 0
        };
    }

    /**
     * 获取升级所需经验
     */
    private getExpNeededForLevel(level: number): number {
        return level * 100; // 简化的经验公式
    }

    /**
     * 获取技能升级所需经验
     */
    private getSkillExpNeeded(level: number): number {
        return level * 50; // 简化的技能经验公式
    }
}
